package annotation

import (
	"go/ast"
)

// SingleFileEntryVisitor 这部分和课堂演示差不多，但是我建议你们自己试着写一些
type SingleFileEntryVisitor struct {
	file *fileVisitor
}

func (s *SingleFileEntryVisitor) Get() File {
	return s.file.Get()
}

func (s *SingleFileEntryVisitor) Visit(node ast.Node) ast.Visitor {
	file, ok := node.(*ast.File)
	if ok {
		//
		fv := &fileVisitor{ans: newAnnotations(file, file.Doc), types: []*typeVisitor{}}
		s.file = fv
		return fv
	}
	return s
}

type fileVisitor struct {
	ans     Annotations[*ast.File]
	types   []*typeVisitor
	visited bool
}

func (f *fileVisitor) Get() File {
	Types := make([]Type, 0, len(f.types))
	for _, tyVistor := range f.types {
		Types = append(Types, tyVistor.Get())
	}

	return File{
		f.ans,
		Types,
	}
}

func (f *fileVisitor) Visit(node ast.Node) ast.Visitor {
	typeNode, ok := node.(*ast.TypeSpec)
	if ok {
		//
		fv := &typeVisitor{ans: newAnnotations(typeNode, typeNode.Doc), fields: []Field{}}
		f.types = append(f.types, fv)
		return fv
	}
	return f
}

type File struct {
	Annotations[*ast.File]
	Types []Type
}

type typeVisitor struct {
	ans    Annotations[*ast.TypeSpec]
	fields []Field
}

func (t *typeVisitor) Get() Type {
	return Type{
		t.ans,
		t.fields,
	}
}

func (t *typeVisitor) Visit(node ast.Node) (w ast.Visitor) {
	//node.(*ast.FuncType)
	switch fieldNode := node.(type) {
	case *ast.Field:
		if fieldNode.Doc == nil {
			// 函数参数和返回值也是 *ast.Field 类型，这里过滤掉这些
			return t
		}
		field := Field{
			newAnnotations(fieldNode, fieldNode.Doc),
		}
		t.fields = append(t.fields, field)
		return t
	default:
		return t
	}
}

type Type struct {
	Annotations[*ast.TypeSpec]
	Fields []Field
}

type Field struct {
	Annotations[*ast.Field]
}
